/**************************************************************************
 * Copyright (C) 2017-2017  Unisound
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 **************************************************************************
 *
 * Description : user_pwm.c
 * Author      : shangjinlong@unisound.com
 * Date        : 2020.04.27
 *
 **************************************************************************/
#include "uni_hal_pwm.h"
#include "user_pwm.h"

#define TAG             "user_pwm"
#define HZ_MAX          (45056000)

enum pwm_status {
  ePWM_IDLE = 0,
  ePWM_INIT,
  ePWM_START,
  ePWM_STOP,
  ePWM_PAUSE,
  ePWM_RESUME,
};

struct user_pwm_config {
  uni_u32         hz;
  uni_u8          duty;
  uni_bool        is_high_duty;
  enum pwm_status status;
};

static struct user_pwm_config pwm_configs[PWM_NUM_MAX] = {0};

static void _set_duty(USER_PWM_NUM num, uni_u8 duty) {
  //根据实际的上升沿还是下降沿做适配
  pwm_configs[num].duty = pwm_configs[num].is_high_duty ? duty : 100 - duty;
}

static uni_bool _is_num_valid(USER_PWM_NUM num) {
  return (num >= PWM_NUM_0 && num < PWM_NUM_MAX);
}

int user_pwm_init(USER_PWM_NUM num, uni_u32 hz, uni_bool is_high_duty) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (hz >= HZ_MAX) {
    LOGE(TAG, "only support max hz[%d]", HZ_MAX - 1);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_IDLE) {
    LOGE(TAG, "cannot reinit pwm, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  pwm_configs[num].hz           = hz;
  pwm_configs[num].is_high_duty = is_high_duty;
  pwm_configs[num].status       = ePWM_INIT;
  return 0;
}

int user_pwm_final(USER_PWM_NUM num) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status == ePWM_IDLE) {
    LOGE(TAG, "cannot finalize pwm, not init actually");
    return -1;
  }

  if (pwm_configs[num].status == ePWM_START ||
      pwm_configs[num].status == ePWM_RESUME) {
    uni_hal_pwm_disable(num);
  }

  memset(&pwm_configs[num], 0, sizeof(struct user_pwm_config));
  return 0;
}

int user_pwm_start(USER_PWM_NUM num, uni_u8 duty) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_INIT &&
      pwm_configs[num].status != ePWM_STOP) {
    LOGE(TAG, "cannot start pwm, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  _set_duty(num, duty);
  uni_hal_pwm_start(num, pwm_configs[num].hz, pwm_configs[num].duty);

  pwm_configs[num].status = ePWM_START;
  return 0;
}

int user_pwm_stop(USER_PWM_NUM num) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_START &&
      pwm_configs[num].status != ePWM_RESUME) {
     LOGE(TAG, "cannot stop pwm, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  uni_hal_pwm_disable(num);

  pwm_configs[num].status = ePWM_STOP;
  return 0;
}

int user_pwm_pause(USER_PWM_NUM num) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_START &&
      pwm_configs[num].status != ePWM_RESUME) {
    LOGE(TAG, "cannot pause pwm, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  uni_hal_pwm_disable(num);

  pwm_configs[num].status = ePWM_PAUSE;
  return 0;
}

int user_pwm_resume(USER_PWM_NUM num) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_PAUSE) {
    LOGE(TAG, "cannot resume pwm, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  uni_hal_pwm_start(num, pwm_configs[num].hz, pwm_configs[num].duty);
  pwm_configs[num].status = ePWM_RESUME;
  return 0;
}

int user_pwm_change_duty(USER_PWM_NUM num, uni_u8 duty) {
  if (!_is_num_valid(num)) {
    LOGE(TAG, "pwm num[%d] invalid", num);
    return -1;
  }

  if (pwm_configs[num].status != ePWM_START &&
      pwm_configs[num].status != ePWM_RESUME) {
    LOGE(TAG, "cannot change duty, current status[%d]", pwm_configs[num].status);
    return -1;
  }

  _set_duty(num, duty);
  uni_hal_pwm_disable(num);
  uni_hal_pwm_start(num, pwm_configs[num].hz, pwm_configs[num].duty);
  return 0;
}

